﻿using System;
using System.Collections.Generic;
using System.Text;
using Mighty.Common;
using System.Collections;

namespace Mighty.Brain
{
    /// <summary>
    /// 기본Brain. 모든 Brain의 기본이 되는 Brain이다. 모든 Brain은 이 클래스를 상속받아야만 한다.
    /// 게임에 관련된 모든 정보를 가지고 있는 gameInfo 속성과 게임으로부터 호출되는 15개의 함수(이벤트)로 구성되어 있다.
    /// 게임으로부터 호출되는 15개의 함수는 다음과 같다.
    /// 
    ///        GameStartEvent,             // (모두) 게임시작
    ///        BettingReadyEvent,          // (모두) 베팅시작, 카드를 이미 나누어 주었다
    ///        BettingTicEvent,            // (개인) 베팅차례
    ///        BettingTalkEvent,           // (모두) 다른사람의 베팅 정보
    ///        BettingCompleteEvent,       // (모두) 베팅완료, 주공이 정해졌다
    ///        ChoiceCardEvent,            // (주공) 카드선택, 13장의 카드중 10장의 카드선택
    ///        LastBettingEvent,           // (주공) 최종베팅정보, 기루다무늬변경가능
    ///        LastBettingTalkEvent,       // (모두) 주공의 최종베팅정보
    ///        ChoiceFriendEvent,          // (주공) 프랜드선택
    ///        ChoiceFriendTalkEvent,      // (모두) 주공의 프랜드 정보
    ///        RoundReadyEvent,            // (모두) 각라운드의시작
    ///        RoundTicEvent,              // (각자) 카드낼차례
    ///        RoundCardThrowEvent,        // (모두) 다른사람의 카드 정보
    ///        RoundCompleteEvent,         // (모두) 각라운드의종료
    ///        GameEndEvent                // (모두) 게임의 종료
    /// </summary>
    public class BasicBrain
    {
        /// <summary>
        /// 각 플레이어가 가지게 되는 게임에 대한 정보, 각 이벤트가 호출되기 전에 gameInfo에는 항상 최신의 정보가
        /// 업데이트되어 있다
        /// </summary>
        public GameInfo gameInfo;

        /// <summary>
        /// 게임시작
        ///  * 매 게임마다 초기화해야할 코드가 있다면 여기에 넣어라
        /// </summary>
        public virtual void GameStartEvent()
        {
        }

        /// <summary>
        /// 베팅시작
        ///  * 카드를 나누어 주고 호출된다. gameInfo.myCards를 참고
        /// </summary>
        public virtual void BettingReadyEvent()
        {
        }

        /// <summary>
        /// 베팅차례
        ///  * 지금까지 배팅된 정보(gameInfo.bettingHistory) 또는 마지막 pass가 아닌 베팅정보 gameInfo.betting를 참고하여 베팅을 결정한다
        /// </summary>
        /// <remarks>
        /// [기본행동] 베팅리밋(betting.limit)이 15이하 이면 베팅리밋을 +1하고 노기루다(Giruda.NoGiruda)로 베팅한다
        /// </remarks>
        public virtual Betting BettingTicEvent()
        {
            Betting betting = new Betting();

            betting.isPass = true;
            if (gameInfo.betting.limit > 0)
            {
                Betting previousBetting = gameInfo.betting;
                if (previousBetting.limit < 15)
                {
                    betting.isPass = false;
                    betting.giruda = Giruda.NoGiruda;
                    betting.limit = previousBetting.limit + 1;
                }
            }
            else
            {
                betting.isPass = false;
                betting.giruda = Giruda.NoGiruda;
                betting.limit = 13;
            }
            return betting;
        }


        /// <summary>
        /// 다른사람의 베팅 정보
        /// </summary>
        public virtual void BettingTalkEvent()
        {
        }

        /// <summary>
        /// 베팅완료, 주공이 정해졌다. 베팅이 끝났을 경우 처리할 코드가 있다면 여기에 하라.
        /// </summary>
        public virtual void BettingCompleteEvent()
        {
        }

        /// <summary>
        /// (주공)카드선택, 13장의 카드중 10장의 카드선택. 버릴3장의 카드에 cmdRemove=true로 설정해주어야 한다
        /// 만약 정확히 3장의 카드가 선택되지 않았을 경우에는 새로추가된 3장의 카드가 그대로 버려진다.
        /// ChoiceCardEvent 가 호출된 후에는 선택된 10장의 카드는 myCards[0]부터 차례대로 배치되고 버려진 3장의 카드는
        /// myCards[10]에서부터 배치되어 나중에 어떤 카드가 버려졌는지 알수 있게 해준다
        /// </summary>
        /// <remarks>
        /// [기본행동] 추가된 3장의 카드를 그대로 버린다
        /// </remarks>
        public virtual HandedCard[] ChoiceCardEvent()
        {
            for (int i = 0; i <= 9; i++)
            {
                gameInfo.myCards[i].cmdRemove = false;
            }
            for (int i = 10; i <= 12; i++)
            {
                gameInfo.myCards[i].cmdRemove = true;
            }
            return gameInfo.myCards;
        }


        /// <summary>
        /// 최종베팅정보, 기루다무늬변경가능. 기루다를 변경할 경우 최소+2된 limit정보를 리턴해야 한다
        /// </summary>
        /// <remarks>
        /// [기본행동] 아무런 변경도 하지 않는다
        /// </remarks>
        public virtual Betting LastBettingEvent()
        {
            return gameInfo.betting;
        }

        /// <summary>
        /// 주공의 최종베팅정보
        /// </summary>
        public virtual void LastBettingTalkEvent()
        {
        }

        /// <summary>
        /// (주공)프랜드선택. 프랜드를 선택하는 방법은 노프랜드(FriendPlayer.HowToSelect.nofriend),
        /// 초구프랜드(FriendPlayer.HowToSelect.firstwin),카드프랜드(FriendPlayer.HowToSelect.card)가 있다.
        /// </summary>
        /// <remarks>
        /// [기본행동] 초구프랜드를 선택한다
        /// </remarks>
        public virtual FriendPlayer ChoiceFriendEvent()
        {
            gameInfo.friend.howToSelect = FriendPlayer.HowToSelect.firstwin;
            return gameInfo.friend;
        }

        /// <summary>
        /// 주공의 프랜드 정보
        /// </summary>
        public virtual void ChoiceFriendTalkEvent()
        {
        }

        /// <summary>
        /// 각라운드의시작
        ///  * 매라운드마다 초기화할 코드가 있다면 이부분에 들어가게 된다
        /// </summary>
        public virtual void RoundReadyEvent()
        {

        }

        /// <summary>
        /// 카드낼차례
        ///  * 각 사용자의 턴에 한번씩 호출되며 낼 카드를 결과값으로 리턴해야 한다. 
        ///  * 사용가능한 카드에는 myCards[i].isPossible 속성이 true로 설정되어 있다. 
        ///  * 만약 사용불가능한 카드를 낼 경우에 시스템은 카드배열에서 제일 처음 만나는 사용가능한 카드를 골라서 사용한다
        /// </summary>
        /// <remarks>
        /// [기본행동] 가능한 카드중에서 랜덤하게 하나의 카드를 선택한다
        /// </remarks>
        public virtual HandedCard RoundTicEvent()
        {
            ArrayList possibleCards = new ArrayList();
            foreach (HandedCard card in gameInfo.myCards)
            {
                if (card.isPossible) possibleCards.Add(card);
            }

            Random r = new Random();
            int k = r.Next(possibleCards.Count);

            return (HandedCard)possibleCards[k];
        }

        /// <summary>
        /// 다른사람의 카드 정보
        /// </summary>
        public virtual void RoundCardThrowEvent()
        {
        }

        /// <summary>
        /// 각라운드의종료, 각 라운드가 종료되면 호출된다. 각 라운드의 승자는 gameinfo의 winner를 참조한다
        /// </summary>
        public virtual void RoundCompleteEvent()
        {

        }

        /// <summary>
        /// 게임의 종료, 게임이 종료되었을때 실행될 코드는 여기에 추가한다.
        /// </summary>
        public virtual void GameEndEvent()
        {

        }
    }
}
